package jsprintorbitor.style;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Stroke;

import jsprintorbitor.experiment.graph.AlgGenPair;
import laboratoryQ.computation.flatness.SemanticDiagramData;
import laboratoryQ.draw.DiagramDrawer.DiagramStyleStruct;
import laboratoryQ.style.IStyle;
import laboratoryQ.style.IStyleProperty;
import laboratoryQ.style.IStyleStructure;
import laboratoryQ.style.ReflectionBasedStyle;
import laboratoryQ.style.StyleGenerateUtils;
import laboratoryQ.style.stages.IPropertyFiller;

public class SpOrbStyleFiller implements IPropertyFiller {
	private static final Stroke DEFAULT_STROKE = new BasicStroke(
			1.0f,
			BasicStroke.CAP_BUTT,
			BasicStroke.JOIN_BEVEL, 1.0f,
			null,
			0.0f
		);
	private static final Stroke[] DEFAULT_STROKE_COLL;
	static {
		int n = StyleGenerateUtils.DASHES_COLL.length;
		DEFAULT_STROKE_COLL = new Stroke[n];
		for (int i = 0; i < n; i++) {
			DEFAULT_STROKE_COLL[i] = new BasicStroke(
				1.0f,
				BasicStroke.CAP_BUTT,
				BasicStroke.JOIN_BEVEL, 1.0f,
				StyleGenerateUtils.DASHES_COLL[i],
				0.0f
			);
		}
	}

	private Color[] colors;
	private Stroke[] strokes;

	private Color defaultColor = Color.BLACK;
	private Stroke defaultStroke = DEFAULT_STROKE;

	public SpOrbStyleFiller() {
		this(StyleGenerateUtils.COLORS_COLLECTION, DEFAULT_STROKE_COLL);
	}

	public SpOrbStyleFiller(
			Color[] colors,
			Stroke[] strokes
	) {
		this(colors, strokes,
				Color.BLACK, DEFAULT_STROKE);
	}

	public SpOrbStyleFiller(
			Color[] colors,
			Stroke[] strokes,
			Color defaultColor,
			Stroke defaultStroke
	) {
		this.colors = colors;
		this.strokes = strokes;
		this.defaultColor = defaultColor;
		this.defaultStroke = defaultStroke;
	}

	@Override
	public void fillProperty(IStyleProperty property) {
		DiagramStyleStruct styleStruct = getStyleStruct(property);
		if (styleStruct == null) {
			return;
		}

		styleStruct.diagramStroke = defaultStroke;
		styleStruct.linesColor = defaultColor;

		AlgGenPair semantic = getSemantic(styleStruct);
		if (semantic == null) {
			return;
		}

		styleStruct.diagramStroke = semantic2stroke(semantic);
		styleStruct.linesColor = semantic2color(semantic);
	}

	private AlgGenPair getSemantic(DiagramStyleStruct styleStruct) {
		if (!(styleStruct.diagram instanceof SemanticDiagramData)) {
			return null;
		}
		SemanticDiagramData diagram = (SemanticDiagramData) styleStruct.diagram;
		Object isemantic = diagram.getSemantic();
		assert(isemantic instanceof AlgGenPair);
		AlgGenPair semantic = (AlgGenPair) isemantic;
		return semantic;
	}

	private DiagramStyleStruct getStyleStruct(IStyleProperty property) {
		IStyle istyle = property.getOwnerStyle();
		ReflectionBasedStyle style = (ReflectionBasedStyle) istyle;
		IStyleStructure istyleStruct = style.getStyleStructure();
		if (!(istyleStruct instanceof DiagramStyleStruct)) {
			return null;
		}
		return (DiagramStyleStruct) istyleStruct;
	}

	private Color semantic2color(AlgGenPair semantic) {
		if (semantic.sprinterNo < 0) {
			return defaultColor;
		}
		int sprinterNo = semantic.sprinterNo < colors.length ? semantic.sprinterNo : colors.length - 1;
		return colors[sprinterNo];
	}

	private Stroke semantic2stroke(AlgGenPair semantic) {
		if (semantic.generatorNo < 0) {
			return defaultStroke;
		}
		int generatorNo = semantic.generatorNo < strokes.length ? semantic.generatorNo : strokes.length - 1;
		return strokes[generatorNo];
	}
}
